#ifndef UUID_887CE9BF8B3641C94F3BE685091C7FA5
#define UUID_887CE9BF8B3641C94F3BE685091C7FA5

#include "pixelformat.h"

#include <string.h>
#include <stdlib.h>

#ifdef __cplusplus
extern "C" {
#endif

typedef struct flip_cached_image_data_
{
	char* pixels;
	unsigned width, height;
	unsigned format;
} flip_cached_image_data;

typedef struct flip_image_data_
{
	flip_cached_image_data cached;
	
	flip_upf pf;
} flip_image_data;

void flip_init_image(
	flip_image_data* self,
	unsigned width,
	unsigned height,
	uint32_t format);

void flip_init_image_copy_data(
	flip_image_data* self,
	unsigned width,
	unsigned height,
	uint32_t format,
	void const* data);

void flip_init_image_take_data(
	flip_image_data* self,
	unsigned width,
	unsigned height,
	uint32_t format,
	void* data);
	
void flip_uninit_image(flip_image_data* self);

void flip_image_draw(flip_image_data* src, flip_image_data* dest, unsigned int x, unsigned int y);

#define flip_image_pixels(self) ((self)->cached.pixels)
#define flip_image_width(self) ((self)->cached.width)
#define flip_image_height(self) ((self)->cached.height)

GVL_INLINE void flip_set_pixel(flip_image_data* self, unsigned x, unsigned y, uint32_t pixel)
{
	unsigned width = self->cached.width;
	unsigned height = self->cached.height;
	size_t index = y*width + x;
	void* pixels = flip_image_pixels(self);
	
	if(x >= width || y >= height)
		return; // Out of range

	switch(self->pf.bytespp)
	{
		case 1: ((uint8_t *)pixels)[index] = pixel; break;
		case 2: ((uint16_t*)pixels)[index] = pixel; break;
		case 4: ((uint32_t*)pixels)[index] = pixel; break;
	}
}

GVL_INLINE uint32_t flip_get_pixel(flip_image_data* self, unsigned int x, unsigned int y)
{
	unsigned width = self->cached.width;
	unsigned height = self->cached.height;
	size_t index = y*width + x;
	void const* pixels = flip_image_pixels(self);
	
	if(x >= width || y >= height)
		return 0; // Out of range

	switch(self->pf.bytespp)
	{
		case 1: return ((uint8_t  const*)pixels)[index];
		case 2: return ((uint16_t const*)pixels)[index];
		case 4: return ((uint32_t const*)pixels)[index];
	}
	
	return 0;
}

GVL_INLINE uint32_t flip_get_pixel_repeat(flip_image_data* self, int x, int y)
{
	int width = (int)self->cached.width;
	int height = (int)self->cached.height;
	size_t index;
	void* pixels = flip_image_pixels(self);
	
	if(width == 0 || height == 0)
		return 0;
		
	if(x < 0) x = 0;
	else if(x >= width) x = width - 1;
	
	if(y < 0) y = 0;
	else if(y >= height) y = height - 1;
	
	index = y*width + x;
	
	switch(self->pf.bytespp)
	{
		case 1: return ((uint8_t* )pixels)[index];
		case 2: return ((uint16_t*)pixels)[index];
		case 4: return ((uint32_t*)pixels)[index];
	}
	
	return 0;
}

GVL_INLINE uint32_t flip_unsafe_get_pixel_4(flip_image_data* self, unsigned x, unsigned y)
{
	unsigned width = self->cached.width;
	unsigned height = self->cached.height;
	size_t index = y*width + x;
	void* pixels = flip_image_pixels(self);

	return ((uint32_t*)pixels)[index];
}

GVL_INLINE void flip_unsafe_set_pixel_4(flip_image_data* self, unsigned x, unsigned y, uint32_t pixel)
{
	unsigned width = self->cached.width;
	unsigned height = self->cached.height;
	size_t index = y*width + x;
	void* pixels = flip_image_pixels(self);

	((uint32_t*)pixels)[index] = pixel;
}

#ifdef __cplusplus
} // extern "C"
#endif

#endif // UUID_887CE9BF8B3641C94F3BE685091C7FA5
